// Epoll 服务器端
// 编译方法# g++ -std=c++11 -pthread server.cpp -o server

#include <unordered_map>
#include "general.h"
#include "thread_pool.h"
#include "cJSON.h"
#include "json.hpp"
//#include "general.hpp"

using namespace std;

static const size_t SER_PORT = 9090; /* 默认端口号 */
static const size_t EPOLL_SIZE = 1024;
static const size_t REVTS_SIZE = 128; /* 可执行事件容器的大小 */

// 处理HTTP事务
static void httpserver_io(size_t comm_fd);

// Epoll + 线程池 高并发服务器
class EpollServer
{
private:
	int _listen_fd;			/* 监听套接字 */
	string _ipaddr;			/* 点分十进制 IP 地址 */
	int _port;				/* 监听端口号 */
	shared_ptr<ThreadPool> _th_pool;	/* 线程池 */
public:
	// key: accept()产生的服务套接字；value:first: 客户端IP地址，second: 客户端的端口号
	unordered_map<size_t, pair<string, size_t>> _comm_fd_map;
	mutex _map_mutex;		/* 在线程中操作映射的时候需要加锁 */
	int _epoll_fd;			/* epoll 模型 */
public:

	// 单例模式 全局访问接口
	static EpollServer& get_server()
	{
		static EpollServer _epoll_server;
		return _epoll_server;
	}
	
	// 初始化服务器
	void epoll_server_init(int port, size_t thread_size = 5)
	{
		_listen_fd = -1;
		_port = port;
		_epoll_fd = -1;
		_th_pool = make_shared<ThreadPool>(thread_size);

		// 初始化 套接字
		_socket_bind_listen();
		LOG(INFO, "LISTEN_FD:[" + to_string(_listen_fd) + "] IP:[" + _ipaddr + "]:[" + to_string(_port) + "]");
	}

	EpollServer(EpollServer&) = delete;
	EpollServer(EpollServer&&) = delete;
	EpollServer& operator=(EpollServer&) = delete;
	EpollServer& operator=(EpollServer&&) = delete;

	// 开始运行服务器
	void epoll_run()
	{
		// 初始化 epoll 模型
		_epoll_fd = epoll_create(EPOLL_SIZE);
		if (-1 == _epoll_fd)
		{
			LOG(FATAL, "epoll_create error");
			sys_error("epoll_create: ");
		}

		// 在 epoll 中添加监听套接字
		_epoll_add(_listen_fd, EPOLLIN | EPOLLET);

		while (true)
		{
			// epoll_wait
			epoll_event ep_revts[REVTS_SIZE]; /* 可以执行的集合 */
			int ret_wait = epoll_wait(_epoll_fd, ep_revts, REVTS_SIZE, -1);

			if (-1 == ret_wait)
			{
				LOG(FATAL, "epoll_wail error");
				sys_error("epoll_wait: ");
			}
			else if (0 == ret_wait)
			{
				LOG(WARNING, "epoll_wait timeout");
			}
			else
			{ // 开始正常处理 epoll请求
				_epoll_run(ep_revts, ret_wait);
			}
		}
	}

private:
	EpollServer() = default;
	~EpollServer()
	{
		if (_listen_fd >= 0)
		{
			close(_listen_fd);
		}
	}

	// 初始化套接字
	void _socket_bind_listen()
	{
		_listen_fd = socket(AF_INET, SOCK_STREAM, 0);
		if (-1 == _listen_fd)
		{
			LOG(FATAL, "socket error");
			sys_error("socket: ");
		}

		// 设置端口复用
		int opt = 1;
		setsockopt(_listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

		sockaddr_in ser_addr;
		socklen_t ser_len = sizeof(ser_addr);
		memset(&ser_addr, 0, ser_len);
		ser_addr.sin_family = AF_INET;
		ser_addr.sin_addr.s_addr = INADDR_ANY;
		_ipaddr = inet_ntoa(ser_addr.sin_addr);
		// ser_addr.sin_addr.s_addr = inet_addr(m_ip.c_str());
		ser_addr.sin_port = htons(_port);

		if (0 != bind(_listen_fd, (sockaddr *)&ser_addr, ser_len))
		{
			LOG(FATAL, "bind error");
			sys_error("bind: ");
		}

		if (0 != listen(_listen_fd, LISTENQ))
		{
			LOG(FATAL, "listen error");
			sys_error("listen: ");
		}
	}

	// 往 epoll 模型中添加任务
	void _epoll_add(int fd, uint32_t __events)
	{
		epoll_event ep_ev;
		ep_ev.data.fd = fd;
		ep_ev.events = __events;

		epoll_ctl(_epoll_fd, EPOLL_CTL_ADD, fd, &ep_ev);
	}

	// 在 epoll 模型中删除任务
	void _epoll_del(int fd)
	{
		epoll_ctl(_epoll_fd, EPOLL_CTL_DEL, fd, nullptr);
	}

	// 正常处理 epoll 请求
	void _epoll_run(epoll_event revts[], size_t ret_wait)
	{
		for (int i = 0; i < ret_wait; i++)
		{
			if (revts[i].events & EPOLLIN)
			{
				if (revts[i].data.fd == _listen_fd)
				{ // 等待客户端的接入
					int comm_fd = _server_accept();
				}
				else
				{ // 与客户端进行读写数据操作
					size_t comm_fd = revts[i].data.fd;
					_th_pool->enqueue(httpserver_io, comm_fd);
				}
			}
		}
	}

	// 等待客户端的接入, 如果接入成功，就建立映射
	int _server_accept()
	{
		sockaddr_in cli_addr;
		socklen_t cli_len = sizeof(cli_addr);
		memset(&cli_addr, 0, cli_len);
		int comm_fd = accept(_listen_fd, (sockaddr *)&cli_addr, &cli_len);
		if (comm_fd == -1)
		{
			LOG(WARNING, "accept error");
			return comm_fd;
		}

		// 接入成功，就建立映射
		char cli_ip[41] = "";
		inet_ntop(AF_INET, &cli_addr.sin_addr, cli_ip, 41);
		size_t cli_port = ntohs(cli_addr.sin_port);
		string str(cli_ip);
		LOG(INFO, "COMM_FD:[" + to_string(comm_fd) + "] IP:[" + str + "]:[" + to_string(cli_port) + "] join");
		_comm_fd_map[comm_fd] = make_pair(str, cli_port);
		
		// 有客户端接入成功，在 epoll 中添加这个套接字服务
		_epoll_add(comm_fd, EPOLLIN | EPOLLET);

		return comm_fd;
	}
};

// EpollServer 的全局访问引用
EpollServer& EP_PTR = EpollServer::get_server();

// 开始与已连接的客户端进行读写, 
static void httpserver_io(size_t comm_fd)
{
	char buff[MAXLINE] = "";
	int size = read(comm_fd, buff, MAXLINE);
	
	auto& _map = EP_PTR._comm_fd_map[comm_fd];
	if (size > 0)
	{ // 读入正常，开始处理数据
		//cout << "IP: [" << _map.first << "]:[" << _map.second << "]# " << buff << endl;
	
		cout << buff << endl;
		Json json;  //创建json类
		//json.Json_data_read(buff);  //读取数据
		json.Json_data_analysis(comm_fd, buff);  //解析数据

		//write(comm_fd, buff, size);
	}
	else
	{ // 读入失败，关闭连接
		if (size == -1)
		{
			LOG(ERROR, "COMM_FD:[" + to_string(comm_fd) + "] IP:[" + _map.first
				+ "]:[" + to_string(_map.second) + "] read error");
		}
		close(comm_fd);	// 关闭服务套接字
		LOG(ERROR, "COMM_FD:[" + to_string(comm_fd) + "] IP:[" + _map.first
			+ "]:[" + to_string(_map.second) + "] left");
		{
			lock_guard<mutex> lock(EP_PTR._map_mutex);
			EP_PTR._comm_fd_map.erase(comm_fd);		// 删除映射
			close(comm_fd); 	/* 处理完成，在epoll中删除这个套接字服务 */
		}
	}
}



int main(int argc, char **args)
{
	cout << "server main start ...\n";

	if (argc != 2)
	{
		cout << "Please cin$$ ./httpserver port" << endl;
		cout << "For example$ ./httpserver 9090" << endl;
		return -1;
	}

	EpollServer& ptr = EpollServer::get_server();
	ptr.epoll_server_init(stoi(args[1]), 5);

	ptr.epoll_run();

	cout << "server main end ...\n";
	return 0;
}


